package cn.anecansaitin.jep.interpreter.evaluators;

import cn.anecansaitin.jep.interpreter.Interpreter;
import cn.anecansaitin.jep.parser.ast.node.expression.*;
import cn.anecansaitin.jep.parser.ast.node.expression.literal.IntLiteral;
import cn.anecansaitin.jep.types.TypeInfo;

public class IntEvaluator {
    public static int evaluate(Expression expression) {
        return switch (expression) {
            case Unary unary -> unary(unary);
            case Binary binary -> binary(binary);
            case Ternary ternary -> ternary(ternary);
            case Grouping grouping -> evaluate(grouping.expression());
            case IntLiteral intLiteral -> intLiteral.value();
            default -> throw Interpreter.markError(expression, "未实现的运算符");
        };
    }

    private static int unary(Unary unary) {
        return switch (unary.operator().type()) {
            case UNARY_MINUS -> switch (unary.expression().resultType()) {
                case INT -> -evaluate(unary.expression());
                case CHAR -> -CharEvaluator.evaluate(unary.expression());
                default -> throw Interpreter.markError(unary, "无法将" + unary.operator() + "运算符用于" + unary.expression().resultType());
            };
            case UNARY_PLUS -> switch (unary.expression().resultType()) {
                case INT -> +evaluate(unary.expression());
                case CHAR -> +CharEvaluator.evaluate(unary.expression());
                default -> throw Interpreter.markError(unary, "无法将" + unary.operator() + "运算符用于" + unary.expression().resultType());
            };
            case BIT_NOT -> switch (unary.expression().resultType()) {
                case INT -> ~evaluate(unary.expression());
                case CHAR -> ~CharEvaluator.evaluate(unary.expression());
                default -> throw Interpreter.markError(unary, "无法将" + unary.operator() + "运算符用于" + unary.expression().resultType());
            };
            default -> throw Interpreter.markError(unary, "未实现的运算符");
        };
    }

    private static int binary(Binary binary) {
        return switch (binary.operator().type()) {
            case BIT_LEFT -> bitLeft(binary);
            case BIT_RIGHT -> bitRight(binary);
            case BIT_RIGHT_UNSIGNED -> bitRightUnsigned(binary);
            case PLUS -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue + evaluate(right);
                            case CHAR -> leftValue + CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue + evaluate(right);
                            case CHAR -> leftValue + CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case MINUS -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue - evaluate(right);
                            case CHAR -> leftValue - CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue - evaluate(right);
                            case CHAR -> leftValue - CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case MULTIPLY -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue * evaluate(right);
                            case CHAR -> leftValue * CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue * evaluate(right);
                            case CHAR -> leftValue * CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case DIVIDE -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue / evaluate(right);
                            case CHAR -> leftValue / CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue / evaluate(right);
                            case CHAR -> leftValue / CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case MODULO -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue % evaluate(right);
                            case CHAR -> leftValue % CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue % evaluate(right);
                            case CHAR -> leftValue % CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            default -> throw Interpreter.markError(binary, "未实现的运算符");
        };
    }

    private static int ternary(Ternary ternary) {
        boolean condition = BooleanEvaluator.evaluate(ternary.condition());
        Expression trueExpression = ternary.trueValue();
        Expression falseExpression = ternary.falseValue();

        if (condition) {
            return switch (trueExpression.resultType()) {
                case INT -> evaluate(trueExpression);
                case CHAR -> CharEvaluator.evaluate(trueExpression);
                default -> throw Interpreter.markError(ternary, "不支持的表达式结果类型");
            };
        } else {
            return switch (falseExpression.resultType()) {
                case INT -> evaluate(falseExpression);
                case CHAR -> CharEvaluator.evaluate(falseExpression);
                default -> throw Interpreter.markError(ternary, "不支持的表达式结果类型");
            };
        }
    }

    private static int bitLeft(Binary binary) {
        Expression left = binary.left();
        Expression right = binary.right();
        TypeInfo leftType = left.resultType();
        TypeInfo rightType = right.resultType();

        return switch (leftType) {
            case CHAR -> {
                char leftValue = CharEvaluator.evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue << CharEvaluator.evaluate(right);
                    case INT -> leftValue << evaluate(right);
                    case LONG -> leftValue << LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case INT -> {
                int leftValue = evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue << CharEvaluator.evaluate(right);
                    case INT -> leftValue << evaluate(right);
                    case LONG -> leftValue << LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
        };
    }

    private static int bitRight(Binary binary) {
        Expression left = binary.left();
        Expression right = binary.right();
        TypeInfo leftType = left.resultType();
        TypeInfo rightType = right.resultType();

        return switch (leftType) {
            case CHAR -> {
                char leftValue = CharEvaluator.evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue >> CharEvaluator.evaluate(right);
                    case INT -> leftValue >> evaluate(right);
                    case LONG -> leftValue >> LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case INT -> {
                int leftValue = evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue >> CharEvaluator.evaluate(right);
                    case INT -> leftValue >> evaluate(right);
                    case LONG -> leftValue >> LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
        };
    }

    private static int bitRightUnsigned(Binary binary) {
        Expression left = binary.left();
        Expression right = binary.right();
        TypeInfo leftType = left.resultType();
        TypeInfo rightType = right.resultType();

        return switch (leftType) {
            case CHAR -> {
                char leftValue = CharEvaluator.evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue >>> CharEvaluator.evaluate(right);
                    case INT -> leftValue >>> evaluate(right);
                    case LONG -> leftValue >>> LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case INT -> {
                int leftValue = evaluate(left);

                yield switch (rightType) {
                    case CHAR -> leftValue >>> CharEvaluator.evaluate(right);
                    case INT -> leftValue >>> evaluate(right);
                    case LONG -> leftValue >>> LongEvaluator.evaluate(right);
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
        };
    }
}